k8s 如何实现负载均衡? 您所在的位置:网站首页 docker 负载均衡方案 k8s 如何实现负载均衡?

k8s 如何实现负载均衡?

2023-07-19 05:40| 来源: 网络整理| 查看: 265

文章目录 一、四层与七层1、四层负载均衡2、七层负载均衡 二、四层负载均衡实现:kube-proxy1、userspace 模式2、iptables 模式3、ipvs 模式 三、七层负载均衡实现: Ingress

一、四层与七层 1、四层负载均衡

负载均衡器用 ip+port 接收请求,再直接转发到后端对应服务上;

工作在传输层 ;

客户端和服务器之间建立一次TCP连接,而负载均衡设备只是起到一个类似路由器的转发动作。

2、七层负载均衡

负载均衡器根据 虚拟的 url 或主机名 来接收请求,经过处理后再转向相应的后端服务上; 工作在应用层 ;

七层负载均衡需要建立两次 TCP 连接, client 到 LB,LB根据消息中的内容( 比如 URL 或者 cookie 中的信息 )来做出负载均衡的决定; 然后,建立 LB 到 server 的连接。

负载均衡设备需要先代理最终的服务器和客户端建立 TCP 连接后,才可能接收到客户端发送的真正应用层内容的报文, 然后再根据该报文中的特定字段,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器。

具有七层负载均衡功能的设备通常也被称为反向代理服务器。

在这里插入图片描述

二、四层负载均衡实现:kube-proxy

K8s 的内部服务发现是基于 DNS 解析实现的, 默认解析到一个稳定虚拟 IP (Service),该虚拟 IP 再通过 kube_proxy 将流量均衡到后端 Pods 上。 ( Pod 的 IP 可能会随着 Pod 的重建而变动,但 Service 的 IP 是稳定的 )

kube-proxy 是 k8s 原生组件,主要通过 NodePort 方式暴露服务。

NodePort 方式是什么呢? k8s 能保证在任意 Pod 挂掉时自动启动一个新的,甚至是动态扩容,这就意味着 Pod IP 是会动态变化的; 因此这个 Pod IP 你不适合暴露出去, 而 Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载这些 Pod IP; 因此对外只暴露 Service IP 就行了; 这就是 NodePort 模式,即在每个节点 node 上起一个端口,然后转发到内部 Pod IP 上。

上面提到的这个稳定虚拟 IP 就是一个 ClusterIP 类型的 Service, 这个 Service 会根据 kube-proxy 的代理模式的不同,有不同的性能表现:

1、userspace 模式

v1.0及之前版本的默认模式; 在 userspace 模式下,service 的请求会先从用户空间进入内核 iptables,然后再回到用户空间, 由 kube-proxy 完成后端 Endpoints 的选择和代理工作,这样流量从用户空间进出内核带来的性能损耗是不可接受的。

userspace 模式工作流程如下图:

请求到达 iptables 时会进入内核,而 kube-proxy 监听是在用户态, 这样请求就形成了从用户态到内核态再返回到用户态的传递过程, 降低了服务性能。

因此,userspace 性能差。

2、iptables 模式

v1.1 版本中开始增加了 iptables mode,并在 v1.2 版本中正式取代 userspace 成为默认模式;

通过 Iptables 实现一个四层 TCP NAT ; kube_proxy 只负责创建 iptables 的 nat 规则,不负责流量转发。

这种基于 iptables 的负载均衡,虽然操作起来比较简单,但是当集群规模大导致 iptables rules 多起来的时候, 这种基于 iptables 的负载均衡的性能就比较差了。

当添加一个 service 的时候, iptables 命令行工具需要从内核中读取当前所有的 service 列表, 然后编辑列表, 最后再将新的列表传入内核。 假如要添加 N 个 service,复杂度为 O(N^2) 。

在转发面上, 所有 service ip 地址组成了一个 list, 每一个报文都需要查找这个 list,命中后才能执行规则。 假如一个 ip 在 list 末尾,需遍历 N 次。复杂度为 O(N/2)。

iptables 模式工作流程如下图: 在这里插入图片描述

iptables 模式虽然克服了 userspace 那种 内核态–用户态 之间反复传递的缺陷, 但是在集群规模大的情况下,iptables rules 过多会导致性能显著下降。

因此,iptables 性能勉强适中 。

3、ipvs 模式

在 1.8 以上的版本中,kube-proxy 组件增加了 ipvs 模式;

ipvs 基于 NAT 实现,不创建反向代理, 也不创建 iptables 规则,通过 netlink 创建规则; 而 netlink 通过 hashtable 组织 service,其控制面和转发面的性能都是 O(1) 的,而且直接工作在内核态,因此在性能上比 userspace 和 iptables 都更优秀。

ipvs 模式工作流程如下图: 在这里插入图片描述

因此,ipvs 可谓是性能与负载均衡兼得。

另外, ipvs 还可通过 --ipvs-scheduler 指定负载均衡算法,有多种算法可选, 详情可参考: ipvs-based-in-cluster-load-balancing

kube-proxy 的代理模式,可通过指定 --proxy-mode 参数来配置。

四层这种负载均衡方式存在缺陷:

Service可能有很多,如果每个都绑定一个 node 主机端口的话,主机则需要开放外围的端口进行服务调用,管理上会比较混乱。

比较优雅的方式是通过一个外部的负载均衡器,比如 nginx ,绑定固定的端口比如80,然后根据域名/服务名向后面的Service ip转发, 但是这里对问题在于: 当有新服务加入的时候如何修改 Nginx 配置? 手动改或者 Rolling Update Nginx Pod 都是不现实的。

对于这个问题, k8s 给出的七层解决方案是 Ingress。

三、七层负载均衡实现: Ingress

Ingress 是 k8s 的一种资源对象, 该对象允许外部访问 k8s 服务, 通过创建规则集合来配置访问权限,这些规则定义了哪些入站连接可以访问哪些服务; Ingress 仅支持 HTTP 和 HTTPS 协议; ingress 可配置用于提供外部可访问的服务 url、负载均衡流量、SSL终端和提供虚拟主机名配置。

ingress 的工作流程如下; 在这里插入图片描述

ingress-controller 是实现反向代理和负载均衡的程序, 通过监听 Ingress 这个 api 对象里的配置规则并转化成 Nginx 的配置 , 然后对外部提供服务

Ingress 对于上面提到的 “如何修改 Nginx 配置” 这个问题的解决方案是: 把 “修改 Nginx 配置各种域名对应哪个 Service ” 这些动作抽象为一个 Ingress 对象, 然后直接改 yml 创建/更新就行了,不用再修改 nginx 。

而 ingress-controller 通过与 k8s API 交互,动态感知集群中 Ingress 规则的变化并读取它, 然后按照模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后再 reload 一下生效。

大概的访问路径如下:

用户访问 --> LB --> ingress-nginx-service --> ingressController-ingress-nginx-pod --> ingress字段中调用的后端pod

注意后端 pod 的 service 只提供 pod 归类, 归类后 ingress 会将此 service 中的后端 pod 信息提取出来, 然后动态注入到 ingress-nginx-pod 中的 ingress 字段中, 如此,后端 pod 就能被调用了。

参考文档:

通过Ingress提供7层服务访问

负载均衡基础知识

官方 Ingress 文档



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有